package com.ziki.test.crypto;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import com.ziki.common.util.io.Out;

public class RSAHelper {
    
    /**
     * 得到公钥
     * 
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }
    
    /**
     * 得到私钥
     * 
     * @param key
     *            密钥字符串（经过base64编码）
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }
    
    /**
     * 得到密钥字符串（经过base64编码）
     * 
     * @return
     */
    public static String getKeyString(Key key) throws Exception {
        byte[] keyBytes = key.getEncoded();
        String s = (new BASE64Encoder()).encode(keyBytes);
        return s;
    }
    
    /**
     * 解密
     * 
     * @param strCrypt
     * @param publicKey
     * @return
     */
    public static String decrypt(String strCrypt, String publicKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            byte[] keyBytes = hexToByte(publicKey);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey key = keyFactory.generatePublic(keySpec);
            // 解密
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] enBytes = hexToByte(strCrypt);
            byte[] deBytes = cipher.doFinal(enBytes);
            return new String(deBytes, "GBK");
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
    
    /**
     * 加密
     * 
     * @param strText
     * @param privateKey
     * @return
     */
    public static String encrypt(String strText, String privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            byte[] keyBytes = hexToByte(privateKey);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey key = keyFactory.generatePrivate(keySpec);
            // 加密
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] strBytes = strText.getBytes("GBK");
            byte[] enBytes = cipher.doFinal(strBytes);
            return byteToHexStr(enBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
    
    private static String byteToHexStr(byte b) {
        String s = Integer.toHexString(b & 0xFF).toUpperCase();
        if (s.length() == 1) {
            s = "0" + s;
        }
        return s;
    }
    
    private static String byteToHexStr(byte[] bytearr) {
        if (bytearr == null)
            return "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytearr.length; i++) {
            byte b = bytearr[i];
            sb.append(byteToHexStr(b));
        }
        return sb.toString();
    }
    
    private static byte[] hexToByte(String s) {
        if (s == null)
            return null;
        byte[] bts = new byte[s.length() / 2];
        for (int i = 0, j = 0; j < bts.length; j++) {
            try {
                bts[j] = (byte) Integer.parseInt(s.substring(i, i + 2), 16);
            } catch (NumberFormatException e) {
                bts[j] = 0x00;
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
            i += 2;
        }
        return bts;
    }
    
    public static void main(String[] args) throws Exception {
        // test();
        // Common.opn(encrypt("我们都很好！邮件：@sina.com","30820275020100300D06092A864886F70D01010105000482025F3082025B02010002818100C4C2D6105867405814030AD675956101A20F37C048DB4568DB764BE4F0FC52C70DD50A262AC1EE0AC9D3895BE55813C3C02130F3E66E743C3ED4362A72F1B43CE3F7A314410EDE0D18DD8A0FC0BCB736C2F987CED97ECC12031E2B9685B327082B459E0D37C1DE7175A41C56B5EE3423A4BAEE56FEC4CCA36A53C3180FA13EAD02030100010281800786D87F79924190DCFB1CD00561787B828288846F850BCBAE118167B99C3D6265F20F58546C64B9BEECBBA56B498A4003BA814FE331B87A9180B6ADBB05E9FA15127DD4B1A1CEE53401856DDCE9FAEA131CBE19530A2B0080E349FF5D0688292E31710DAFB68428D6A987B925BC203DB6AECE93F75D89E755587C3EB4162301024100F6F9353EC541CB103F9BC92446F8A3A9638CF3FF7AA02076EBFC7131CC5D968116DAE8AA0C7B3AC2C9DD9D4194062BD23FD1B214D92870B79B8164376604C2C1024100CBF3D1AEBC2F0CC1F05CDF1B3AE13248716A350A9524EBAA36E911058D212937B37271AC3457E8E12230A7DBE6DB454BE346705C16F4F77434F45075D13F72ED0240153E283346FA3AC222067F4D8C81346A8C7282463640F1A9E8F064B818D0EFF2188A29BAFEA9D6CB0C5BF07BC484A75E4538FF2D45E47195895D9EC619134DC102404C3B663499C23C528135356F4822C458AF8BB327B1778B5EA407998529AB2B6CD67600670D698E72180577B88A218B55422E21F149E3665AD93038A2D10396410240679DE1BF3E8195C1A450D71FF43EE880F057B5A54BD9DFBF81699F23273EB13DB2764EAD0E7DD7FF1F2081AD0510A6DCC4729CF14F8BE731AEB8E5FCDB4CA7F1"));
        Out.println(decrypt("8DD2298A44C90FBAB9F171C1E2ED025A9746C7FD5EFA7D427757CA1944C0BFD4D2B9E2BE4952D3018E3620D07376C7163F55D08FA7E05163B8FA49D261EE2647C9AEDA694580EB2C63666E56A24641B400D3EF5619E8E81DA62486ECB93F98A1405A5ABD4C7465F467EE421458FC3853C7B1EB334E1EB692FBBC3ED78F5E328D", "30819F300D06092A864886F70D010101050003818D0030818902818100C4C2D6105867405814030AD675956101A20F37C048DB4568DB764BE4F0FC52C70DD50A262AC1EE0AC9D3895BE55813C3C02130F3E66E743C3ED4362A72F1B43CE3F7A314410EDE0D18DD8A0FC0BCB736C2F987CED97ECC12031E2B9685B327082B459E0D37C1DE7175A41C56B5EE3423A4BAEE56FEC4CCA36A53C3180FA13EAD0203010001"));
    }
    
    private static void test() throws NoSuchAlgorithmException, Exception, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 密钥位数
        keyPairGen.initialize(1024);
        // 密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        
        // 公钥
        PublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        Out.println("getAlgorithm:\n" + publicKey.getAlgorithm());
        Out.println("getFormat:\n" + publicKey.getFormat());
        Out.println("getEncoded:\n" + byteToHexStr(publicKey.getEncoded()));
        // 私钥
        PrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Out.println("getAlgorithm:\n" + privateKey.getAlgorithm());
        Out.println("getFormat:\n" + privateKey.getFormat());
        Out.println("getEncoded:\n" + byteToHexStr(privateKey.getEncoded()));
        String publicKeyString = getKeyString(publicKey);
        System.out.println("public:\n" + publicKeyString);
        Out.print(publicKey.getEncoded());
        String privateKeyString = getKeyString(privateKey);
        System.out.println("private:\n" + privateKeyString);
        
        // 加解密类
        Cipher cipher = Cipher.getInstance("RSA");// Cipher.getInstance("RSA/ECB/PKCS1Padding");
        
        // 明文
        byte[] plainText = "我们都很好！邮件：@sina.com".getBytes();
        
        // 加密
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] enBytes = cipher.doFinal(plainText);
        System.out.println(new String(enBytes));
        Out.print(enBytes);
        
        // 通过密钥字符串得到密钥
        publicKey = getPublicKey(publicKeyString);
        privateKey = getPrivateKey(privateKeyString);
        
        // 解密
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] deBytes = cipher.doFinal(enBytes);
        
        publicKeyString = getKeyString(publicKey);
        System.out.println("public:\n" + publicKeyString);
        
        privateKeyString = getKeyString(privateKey);
        System.out.println("private:\n" + privateKeyString);
        
        String s = new String(deBytes);
        System.out.println(s);
    }
    
}
